package com.spstudio.iforward.end.impl;

import java.io.File;
import java.security.Principal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;

import com.spstudio.iforward.core.bean.PageObject;
import com.spstudio.iforward.core.helper.CandidateStoryQueryResult;
import com.spstudio.iforward.core.helper.DatabaseHelper;
import com.spstudio.iforward.core.interfaces.IQueryResult;
import com.spstudio.iforward.core.qualifier.SPCoreLogged;
import com.spstudio.iforward.end.interfaces.ICandidateStorySessionBeanRemote;
import com.spstudio.iforward.end.interfaces.ISPCoreSystemBeanRemote;
import com.spstudio.iforward.end.util.PictureDownloadUtil;
import com.spstudio.iforward.front.CandidateStory;
import com.spstudio.iforward.front.interfaces.IStorySessionBeanRemote;
import com.spstudio.iforward.qualifier.SPCoreSystemSingleRemoteBean;

/**
 * Session Bean implementation class CandidateStorySessionBean
 */
@Stateless
public class CandidateStorySessionBean implements ICandidateStorySessionBeanRemote {

	@Inject DatabaseHelper helper;
	@Inject Principal principal;
	@Inject @SPCoreLogged Logger log;
	@Inject @SPCoreSystemSingleRemoteBean ISPCoreSystemBeanRemote systemBean;
	@EJB IStorySessionBeanRemote storySessionBeanRemote;
	
	public static final String WEB_HOST_NAME = "http://www.izhuanfa.cn";
	private static final SimpleDateFormat formatYYYYMM = new SimpleDateFormat("yyyyMM");
	private static final SimpleDateFormat formatDDHHMMSS = new SimpleDateFormat("ddhhmmss");
	private static final Pattern imagePattern = Pattern.compile("<img[^>]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>");
	private static final String imageTemplate = "<img style=\"max-width: 100%; height: auto;\" src=\"$$$1$$$\" />";
	/*
	 * INSERT MODE
	 */
	private static final String INSERT_STORY_CANDIDATE = "insert into story_candidate(story_category_id, review_status_id, title, content, comment, create_user_id, create_time, item_source) "
			+ "values(?,?,?,?,?,(select id from users where username = ?),now(),?)";
	private static final String INSERT_PIC_RESOURCE = "insert into pic_resource(story_candidate_id, path1, path2, res_name, thumbnail_flag) values ";
	/*
	 * UPDATE MODE
	 */
	private static final String DELETE_PIC_RESOURCE = "delete from pic_resource where story_candidate_id = ?";
	private static final String SELECT_PIC_FOLDER_PATH = "SELECT distinct path1, path2 FROM pic_resource where story_candidate_id = ?";
	private static final String UPDATE_PIC_STORY_CANDIDATE = "update story_candidate set story_category_id = ?, title = ?, content = ?, comment = ?, item_source = ? where id = ?";
	private static final String UPDATE_CANDIDATE_STORY_REVIEWED = "update story_candidate set review_status_id = 2 where id = ?";
	private static final String QUERY_STORY_ID = "select story_id from story_candidate where id = ?";
	private static final String UPDATE_CANDIDATE_STORY_UNREVIEWED = "update story_candidate set review_status_id = 1, story_id = null where id = ?";
	/*
	 * QUERY CANDIDATE STORY
	 */
	private static final String QUERY_CANDIDATE_STORY_COUNT = "SELECT count(0) FROM story_candidate";
	private static final String QUERY_CANDIDATE_STORY = "SELECT sc.id,sc.story_category_id,sc.review_status_id,sc.story_id,sc.title,sc.create_user_id,sc.create_time,rs.status_name,ca.category_name,users.username"
			+" FROM story_candidate sc,review_status rs,story_category ca,users"
			+" WHERE sc.review_status_id = rs.id and sc.story_category_id = ca.id and sc.create_user_id = users.id ";
	private static final String QUERY_SINGLE_CANDIDATE_STORY = "SELECT id, story_category_id, title, content, comment, item_source FROM story_candidate where id = ?";
	
	/*
	 * DELETE CANDIDATE STORY
	 */
	private static final String DELETE_CANDIDATE_STORY = "delete from story_candidate where id = ?";
	
	private String savedPicturePath1;
	private String savedPicturePath2;
	private List<PicRes> savedPictureList;
	
	@Override
	public int saveCandidateStory(CandidateStory story) {
		
		if (story.getId() != 0){ // update story
			// query picture files
			List<Object[]> result = helper.doQuery(SELECT_PIC_FOLDER_PATH, new Object[]{story.getId()});

			// delete pic_resource
			helper.doDMLOperation(DELETE_PIC_RESOURCE, new Object[]{story.getId()});
			
			// update
			Object[] params = new Object[]{
					story.getCategoryId(),
					story.getTitle(),
					parseHtmlAndDownloadPic(story.getContent()),
					story.getComment(),
					story.getItemSource(),
					story.getId()};
			helper.doDMLOperation(UPDATE_PIC_STORY_CANDIDATE, params);
			savePicResource(story.getId());
			
			// delete picture files
			if (result != null && result.size() != 0) {
				for (Object[] data : result) {
					File folder = new File(systemBean.retrievePictureSavePath() + File.separator + data[0] + File.separator + data[1]);
					if (folder.isDirectory()){
						for(File subFile: folder.listFiles()){
							subFile.delete();
						}
						boolean isDeleteSuccess = folder.delete();
						if (!isDeleteSuccess) {
							log.warning("delete folder failure, " + folder.getAbsolutePath());
						}
					}
				}
			}
			return story.getId();
			
		}else{
			
			Object[] params = new Object[]{
					story.getCategoryId(),
					1,
					story.getTitle(),
					parseHtmlAndDownloadPic(story.getContent()),
					story.getComment(),
					principal.getName(),
					story.getItemSource()};
			int dbPrimaryKey = helper.doDMLOperationWithGeneratedKeyReturn(INSERT_STORY_CANDIDATE, params);
			savePicResource(dbPrimaryKey);
			return dbPrimaryKey;
			
		}
	}
	
	private void savePicResource(int candidateId){
		if (savedPictureList != null && savedPictureList.size() != 0){
			StringBuffer sb = new StringBuffer();
			for (PicRes picRes: savedPictureList){
				sb.append(",(")
				.append(candidateId).append(",'")
					.append(savedPicturePath1).append("','")
					.append(savedPicturePath2).append("','")
					.append(picRes.getResourceUrl()).append("',")
					.append(picRes.isThumbnail())
				.append(")");
			}
			helper.doDMLOperation(INSERT_PIC_RESOURCE + sb.toString().substring(1), null);
		}
	}
	
	private String parseHtmlAndDownloadPic(String html){
		Matcher matcher = imagePattern.matcher(html);
		Map<String, String> map = new HashMap<String, String>();
		List<String> urls = new ArrayList<String>();
		while (matcher.find()){
			map.put(matcher.group(1), matcher.group());
			urls.add(matcher.group(1));
		}
		Date today = new Date();
		savedPicturePath1 = formatYYYYMM.format(today);
		savedPicturePath2 = formatDDHHMMSS.format(today);
		File pictureSavingFolder = new File(systemBean.retrievePictureSavePath() + File.separator + savedPicturePath1 + File.separator + savedPicturePath2);
		if (!pictureSavingFolder.exists()){
			pictureSavingFolder.mkdirs();
		}
		PictureDownloadUtil util = new PictureDownloadUtil(pictureSavingFolder.getAbsolutePath(), urls.toArray(new String[]{}));
		ConcurrentMap<String, String> savedPictureMap = null;
		try{
			savedPictureMap = util.download();
		}catch(InterruptedException e){
			log.log(Level.SEVERE, "downloading pictures time out");
		}
		
		Iterator<String> it = map.keySet().iterator();
		if (savedPictureMap != null) {
			savedPictureList = new ArrayList<PicRes>();
			while (it.hasNext()) {
				String key = it.next();
				if (savedPictureMap.containsKey(key)) {
					html = html.replace(
							map.get(key),
							imageTemplate.replace("$$$1$$$", WEB_HOST_NAME + "/"
											+ savedPicturePath1 + "/"
											+ savedPicturePath2 + "/"
											+ savedPictureMap.get(key)));
					PicRes picRes = new PicRes();
					picRes.setResourceUrl(savedPictureMap.get(key));
					picRes.setThumbnail(key.equals(savedPictureMap.get(PictureDownloadUtil.RECOMMAND_THUMBNAIL)));
					savedPictureList.add(picRes);
				} else {
					html = html.replace(map.get(key), "");
				}
			}
		}
		
		return html;
	}
	
	class PicRes{
		private String resourceUrl;
		private boolean thumbnail;
		public String getResourceUrl() {
			return resourceUrl;
		}
		public void setResourceUrl(String resourceUrl) {
			this.resourceUrl = resourceUrl;
		}
		public boolean isThumbnail() {
			return thumbnail;
		}
		public void setThumbnail(boolean thumbnail) {
			this.thumbnail = thumbnail;
		}
	}

	@Override
	public IQueryResult<CandidateStory> loadMultiCandidateStory(CandidateStory condition, PageObject pageObject) {
		IQueryResult<CandidateStory> returnResult = new CandidateStoryQueryResult();
		
		// query total number
		List<Object[]> result = null;
		if (condition.getTitle() != null && condition.getTitle().length() != 0){
			result = helper.doQuery(QUERY_CANDIDATE_STORY_COUNT + " where title like concat(?, '%')", new Object[]{condition.getTitle()});
		}else{
			result = helper.doQuery(QUERY_CANDIDATE_STORY_COUNT, null);
		}
		if (result != null && result.size() != 0){
			pageObject.setTotalRecordsNumber(0);
		}
		((CandidateStoryQueryResult)returnResult).setPageObject(pageObject);
		
		// query paging data
		Object[] params = new Object[] {
				pageObject.getOffset(),
				pageObject.getMaxRecordsPerPage()
			};
		if (condition.getTitle() != null && condition.getTitle().length() != 0){
			params = new Object[]{
					condition.getTitle(),
					pageObject.getOffset(),
					pageObject.getMaxRecordsPerPage()
			};
			result = helper.doQuery(QUERY_CANDIDATE_STORY + " and sc.title like concat(?, '%')" + " ORDER by sc.id desc limit ?,?", params);
		}else{
			result = helper.doQuery(QUERY_CANDIDATE_STORY + "ORDER by sc.id desc limit ?,?", params);
		}
		List<CandidateStory> listCandidateStory = new ArrayList<CandidateStory>();
		if (result != null && result.size() != 0){
			CandidateStory tempBean = new CandidateStory();
			for(Object[] row: result){
				CandidateStory bean = tempBean.clone();
				bean.setId((Integer)row[0]);
				bean.setCategoryId((Integer)row[1]);
				bean.setReviewStatus((Integer)row[2]);
				bean.setTitle((String)row[4]);
				bean.setCreateUserId((Integer)row[5]);
				bean.setCreateTime(((Timestamp)row[6]).getTime());
				bean.setReviewStatusName((String)row[7]);
				bean.setCategoryName((String)row[8]);
				bean.setCreateUserName((String)row[9]);
				listCandidateStory.add(bean);
			}
		}
		((CandidateStoryQueryResult)returnResult).setListCandidateStory(listCandidateStory);
		return returnResult;
	}

	@Override
	public CandidateStory loadSingleCandidateStory(int storyId) {
		List<Object[]> result = helper.doQuery(QUERY_SINGLE_CANDIDATE_STORY, new Object[]{storyId});
		if (result != null && result.size() != 0){
			CandidateStory bean = new CandidateStory();
			bean.setId((Integer)result.get(0)[0]);
			bean.setCategoryId((Integer)result.get(0)[1]);
			bean.setTitle((String)result.get(0)[2]);
			bean.setContent(((String)result.get(0)[3]).replace(WEB_HOST_NAME, "http://" + systemBean.retrievePictureHttpHost()));
			bean.setComment((String)result.get(0)[4]);
			bean.setItemSource((String)result.get(0)[5]);
			return bean;
		}
		return null;
	}

	@Override
	public boolean setStoryStatusReviewed(int storyId) {
		int effectRowCount = helper.doDMLOperation(UPDATE_CANDIDATE_STORY_REVIEWED, new Object[]{storyId});
		return effectRowCount == 1;
	}

	@Override
	public void deleteCandidateStory(int storyId) {
		// query picture files
		List<Object[]> result = helper.doQuery(SELECT_PIC_FOLDER_PATH, new Object[]{storyId});

		// delete pic_resource
		helper.doDMLOperation(DELETE_PIC_RESOURCE, new Object[]{storyId});
		helper.doDMLOperation(DELETE_CANDIDATE_STORY, new Object[]{storyId});
		// delete picture files
		if (result != null && result.size() != 0) {
			for (Object[] data : result) {
				File folder = new File(systemBean.retrievePictureSavePath() + File.separator + data[0] + File.separator + data[1]);
				if (folder.isDirectory()){
					for(File subFile: folder.listFiles()){
						subFile.delete();
					}
					boolean isDeleteSuccess = folder.delete();
					if (!isDeleteSuccess) {
						log.warning("delete folder failure, " + folder.getAbsolutePath());
					}
				}
			}
		}
	}

	@Override
	public boolean setStoryStatusUnReviewed(int storyId) {
		int effectRowCount = helper.doDMLOperation(UPDATE_CANDIDATE_STORY_UNREVIEWED, new Object[]{storyId});
		return effectRowCount == 1;
	}

	@Override
	public void deletePublishedCandidateStory(int storyId) {
		List<Object[]> result = helper.doQuery(QUERY_STORY_ID, new Object[]{storyId});
		if (result != null && result.size() == 1){
			int story_id = (Integer)result.get(0)[0];
			setStoryStatusUnReviewed(storyId);
			storySessionBeanRemote.deletePublishedStory(story_id);
		}
	}
	
//	public static void main(String args[]){
//		PictureDownloadUtil util = new PictureDownloadUtil("/Users/sp/Desktop/Originals", 
//				new String[]{
//				"http://www.baidu.com/img/baidu_jgylogo3.gif?v=93327100.gif",
//				"http://img0.bdstatic.com/static/common/widget/search_box_search/logo/logo_3b6de4c.png",
//				"http://static.wenku.bdimg.com/static/widget/common/header/search_box/images/logo-wk-137-46_3164f22b.png"
//		});
//		try{
//			ConcurrentMap<String, String> map = util.download();
//			System.out.println(map.size());
//		}catch(Exception e){
//			e.printStackTrace();
//		}
//	}

}
